package org.springframework;


import lombok.extern.slf4j.Slf4j;
import org.springframework.beanFactory.config.BeanFactoryConfig;
import org.springframework.beanFactory.entity.Bean1;
import org.springframework.beanFactory.event.UserService;
import org.springframework.beanLifeCycle.config.beanLifeCycleConfig;
import org.springframework.beanPostProcessor.entity.BeanPostProcessorBean1;
import org.springframework.beanPostProcessor.entity.BeanPostProcessorBean2;
import org.springframework.beanPostProcessor.entity.BeanPostProcessorBean3;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
import org.springframework.context.support.GenericApplicationContext;



@Slf4j
public class Main {


	public static void main(String[] args) {

	}

	/**
	 * beanFactory 和 applicationContext
	 */
	public static void base() {
		// 初始化容器对象
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanFactoryConfig.class);
		// beanFactory为applicationContext的一个成员变量
		// beanFactory管理bean对象
		Object getResourceFormJava = context.getBean("bean1");
		log.info(getResourceFormJava.toString());

		UserService userService = context.getBean(UserService.class);
		userService.register("张三", "123456");


	}


	/**
	 * @Description: 第二讲 beanFactory 关于beanFactory的实现
	 * 1.beanFactory 创建注册 BeanDefinition 并不会扫描注册内部bean 即没有解析@Configuration和@Bean注解功能
	 * 2.beanFactory 后处理器 (BeanFactoryPostProcessor) (org.springframework.context.annotation.internalConfigurationAnnotationProcessor) :
	 * 这个后处理器提供解析@Configuration和@Bean注解功能 此后处理器运行后会先beanFactory内注册带有@Bean的beanDefinition
	 * beanFactory后处理器主要功能就是，补充了一些bean的定义
	 * 3.bean 后处理器(BeanPostProcessor)(org.springframework.context.annotation.internalAutowiredAnnotationProcessor):
	 * 针对Bean的生命周期的各个阶段提供扩展，例如@Autowired 、@Resource…
	 */
	public static void beanFactory() {
		// 初始化对象
		DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
		// 向对象中添加 BeanDefinition (class,scope,初始化,懒加载...)
		AbstractBeanDefinition singleton = BeanDefinitionBuilder.genericBeanDefinition(BeanFactoryConfig.class).setScope("singleton").getBeanDefinition();
		// 将BeanDefinition 注册进bean工厂
		beanFactory.registerBeanDefinition("beanFactoryConfig", singleton);
		// 获取 bean工厂内 将BeanDefinition 的名字
		log.info("输出注册入beanFactory内的beanDefinition");
		for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
			log.info(beanDefinitionName);
		}

		// 给 BeanFactory 添加一些常用的后处理器 internalConfigurationAnnotationProcessor internalAutowiredAnnotationProcessor
		AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
		// 输出 beanFactory 内所有的 beanDefinition
		log.info("");
		log.info("输出添加一些常用后处理器之后beanFactory内的所有beanDefinition");
		for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
			log.info(beanDefinitionName);
		}
		// 获取所有BeanFactory 后处理器 补充将BeanDefinition
		log.info("");
		log.info("使用所有后处理器处理beanFactory内beanDefinition");
		beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().stream().forEach(beanFactoryPostProcessor -> beanFactoryPostProcessor.postProcessBeanFactory(beanFactory));
		log.info("");
		log.info("输出从beanFactory中获取到所有后处理器");
		beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).keySet().stream().forEach(beanFactoryPostProcessor -> log.info(beanFactoryPostProcessor));
		log.info("");
		log.info("输出注册入beanFactory内的beanDefinition");
		for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
			log.info(beanDefinitionName);
		}
		// 输出获取BeanFactory中bean1对象 getBean 会执行 Bean的构造方法
		log.info("");
		// log.info(beanFactory.getBean(BeanPostProcessorBean1.class).getBean2());
		log.info("----------分隔线-------------");
		// bean的后处理器 效果同下部注释代码
		log.info("使用所有后处理器处理beanFactory内beanDefinition");
		beanFactory.getBeansOfType(BeanPostProcessor.class).values()
				.forEach(beanFactory::addBeanPostProcessor);
		/*beanFactory.getBeansOfType(BeanPostProcessor.class).values()
				.forEach(beanPostProcessor -> {
					beanFactory.addBeanPostProcessor(beanPostProcessor);
				});*/
		log.info(beanFactory.getBean(Bean1.class).getBean2().toString());

	}


	/**
	 * @Description: 第三讲 bean的生命周期 见目录 beanLifeCycle
	 * 此目录下包含模板方法示例
	 */
	public static void beanLifeCycle() {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(beanLifeCycleConfig.class);
		context.close();
	}

	/**
	 * @Description: 第四讲 常见的bean处理器 见目录 beanPostProcessor
	 * GenericApplicationContext 干净的容器(还未添加常见的后处理器)
	 */
	public static void beanPostProcessor() {
		// GenericApplicationContext 是一个【干净】的容器，默认不会添加任何后处理器，方便做测试
		// 这里用DefaultListableBeanFactory也可以完成测试，只是会比使用GenericApplicationContext麻烦一些
		GenericApplicationContext context = new GenericApplicationContext();

		// 用原始方法注册三个Bean
		context.registerBean("bean1", BeanPostProcessorBean1.class);
		context.registerBean("bean2", BeanPostProcessorBean2.class);
		context.registerBean("bean3", BeanPostProcessorBean3.class);

		// 设置解析 @Value 注解的解析器 只获取解析器
		context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
		// 添加解析 @Autowired 和 @Value 注解的后处理器 依赖注入时生效
		context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
		// 添加解析 @Resource、@PostConstruct、@PreDestroy 注解的后处理器  依赖注入时生效 @Resource 初始化前  初始化之前 @PostConstruct  销毁前 @PreDestroy
		context.registerBean(CommonAnnotationBeanPostProcessor.class);

		// 初始化容器
		context.refresh();

		// 销毁容器
		context.close();


	}


}
